package com.spgf.model.dao.util;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.archtecture.model.enuns.Mensagem;
import com.archtecture.model.exceptions.NegocioException;
import com.spgf.model.entities.utils.ModelAb;

public abstract class PadraoDAOAb<Model extends ModelAb> {

	private SQLiteDatabase					database;

	private final CustomSQLiteOpenHelper	custonDatabase;

	private final Context					context;

	private Cursor							cursor;

	public PadraoDAOAb(final Context context) {
		this.context = context;
		custonDatabase = new CustomSQLiteOpenHelper(context);
		DatabaseUtil.getInstance().importarBancoDados(context, custonDatabase);
	}

	private void close() {

		DatabaseUtil.getInstance().exportarBancoDados(getContext());

		if (cursor != null && !cursor.isClosed()) {
			cursor.close();
		}

		if (database != null && database.isOpen()) {
			database.close();
		}

		if (custonDatabase != null) {
			custonDatabase.close();
		}
	}

	public Model configurarDependencias(final Model model) throws NegocioException {
		return model;
	}

	protected abstract Model configurarModel(Cursor cursor);

	protected abstract String configurarOrderBy(String pOrderBy);

	protected abstract ContentValues configureContetValues(Model model);

	protected abstract String definirClausuraWhere(Model model);

	protected String definirColunasUnicas(final Model model) throws NegocioException {
		return getNomeTabela() + " = " + model.getCodigo();
	}

	public final void executeDelete(final Model model) {

		openWritable();

		final String where = getColunaCodigo() + " = ? ";
		final String[] args = new String[] {model.getCodigo().toString()};

		getDatabase().delete(getNomeTabela(), where, args);

		close();
	}

	public final Model executeFind(final Model model) throws NegocioException {

		openReadable();

		cursor = getDatabase().query(getNomeTabela(), getColuns(), definirColunasUnicas(model), null, null, null, null);

		final List<Model> models = new ArrayList<Model>();
		while (cursor.moveToNext()) {
			models.add(configurarDependencias(configurarModel(cursor)));
		}

		close();

		if (models.size() > 1) {
			throw new NegocioException(Mensagem.ERRO_MULTIPLOS_RESULTADOS_NA_PESQUISA_UNICA, models.size());
		}

		return models.iterator().next();
	}

	public final List<Model> executeFindAll(final Model model, final String pOrderBy, String where) throws NegocioException {

		openReadable();

		cursor = getDatabase().query(getNomeTabela(), getColuns(), model != null ? where : null, null, null, null,
				configurarOrderBy(pOrderBy));

		final List<Model> models = new ArrayList<Model>();
		while (cursor.moveToNext()) {
			models.add(configurarDependencias(configurarModel(cursor)));
		}

		close();

		return models;
	}

	public final Model executeInsert(final Model model) {

		openWritable();

		final ContentValues values = configureContetValues(model);

		final long insertId = getDatabase().insert(getNomeTabela(), null, values);

		cursor = getDatabase().query(getNomeTabela(), getColuns(), getColunaCodigo() + " = " + insertId, null, null, null, null);
		cursor.moveToFirst();

		final Model newModel = configurarModel(cursor);

		close();

		return newModel;
	}

	public final Model executeUpdate(final Model model) {
		return null;
	}

	protected abstract String getColunaCodigo();

	protected abstract String[] getColuns();

	public Context getContext() {
		return context;
	}

	private SQLiteDatabase getDatabase() {
		return database;
	}

	protected abstract String getNomeTabela();

	protected void openReadable() {
		database = custonDatabase.getReadableDatabase();
	}

	private void openWritable() {
		database = custonDatabase.getWritableDatabase();
	}
}
